from datetime import datetime

from rest_framework import serializers
from django.db.models import F
from django.conf import settings
from django.db.models import F

from apps.common.account.models import Account
from apps.survey_system.question.models import QuestionnaireQuestion, QuestionnaireQsCate, QuestionOption
from utils.data_dict import get_data_dict
from .models import Survey, SurveyAccount, SurveyQuestion, SurveyQuestionCategory, SurveyQuestionOption, SurveyAnswer

questionTypeDict = {
    1: '单选题', 2: '多选题', 3: '简答题', 4: '文件上传题'
}


class SurveyListSerializer(serializers.ModelSerializer):
    start_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
    end_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
    display_score_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")
    created_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M")

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        survey_score = self.context.get('survey_score', None)
        survey_account_count = self.context.get('survey_account_count', None)
        if survey_score is not None:
            ret['survey_score'] = survey_score.get(instance.id, 0)
        if survey_account_count is not None:
            ret['survey_account_count'] = survey_account_count.get(instance.id, 0)

        now = datetime.now()
        ret['account_name'] = instance.account.realname if instance.account else ''
        if now < instance.start_time:
            ret['status'] = '未开始'
        elif now > instance.end_time:
            ret['status'] = '已结束'
        else:
            ret['status'] = '进行中'
        return ret

    class Meta:
        model = Survey
        fields = '__all__'


class SurveyCreateSerializer(serializers.ModelSerializer):
    account = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )  # 默认为当前创建者
    upload_student = serializers.JSONField(write_only=True)
    class_cascader = serializers.JSONField(write_only=True)
    questionnaire = serializers.IntegerField(write_only=True, required=True)

    def validate(self, attrs):
        display_score_type = attrs['display_score_type']
        if display_score_type != 3:
            attrs['display_score_time'] = None
        return attrs

    def create(self, validated_data):
        upload_student = validated_data.pop('upload_student', [])
        class_cascader = validated_data.pop('class_cascader', [])
        questionnaire = validated_data.pop('questionnaire', 0)
        obj = Survey(**validated_data)
        obj.save()

        # 创建该场调查需要填写问卷的人员的信息
        class_code_lst = [i.split('_')[-1] for i in class_cascader]
        account_ids = Account.objects.filter(class_code__in=class_code_lst).values_list('id', flat=True)
        upload_student.extend(account_ids)
        bulk_create_account = []
        account_qs = Account.objects.filter(id__in=upload_student)\
            .values('username', 'realname', 'faculty_code', 'faculty_title', 'major_code', 'major_title', 'class_code',
                    'class_title', 'sex', 'grade_name')
        for i in account_qs:
            bulk_create_account.append(SurveyAccount(survey=obj, **i))
        SurveyAccount.objects.bulk_create(bulk_create_account, batch_size=200)

        # 找出该问卷使用的题目的分类，并在调查中创建
        cate_qs = QuestionnaireQsCate.objects.filter(questionnaire_id=questionnaire)\
            .order_by('sort_num', 'id')\
            .values('id', 'name')
        bulk_create_cate = [SurveyQuestionCategory(survey=obj, category_name=i['name'],
                                                   questionnaire_qs_cate_id=i['id']) for i in cate_qs]
        cate_id_lst = [i['id'] for i in cate_qs]
        # 批量创建后重新查询，因为批量创建没返回新创建数据的id
        SurveyQuestionCategory.objects.bulk_create(bulk_create_cate, batch_size=200)
        survey_qs_cate = SurveyQuestionCategory.objects\
            .filter(survey=obj, questionnaire_qs_cate_id__in=cate_id_lst)\
            .values('id', category_id=F('questionnaire_qs_cate_id'))
        survey_qs_cate_dict = {i['category_id']: i['id'] for i in survey_qs_cate}

        # 找出该问卷使用的题目，并在调查中创建
        question_qs = QuestionnaireQuestion.objects\
            .filter(category__in=cate_id_lst)\
            .order_by('category__sort_num', 'category_id', 'sort_num', 'id')\
            .values('category_id', 'question_id', name=F('question__name'), file=F('question__file'),
                    desc=F('question__desc'), type=F('question__type'), is_required=F('question__is_required'),
                    answer_need_text=F('question__answer_need_text'), answer_need_option=F('question__answer_need_option'),
                    score=F('question__score'), mul_choice_score_type=F('question__mul_choice_score_type'),
                    is_need_limit=F('question__is_need_limit'), limit_choice_count=F('question__limit_choice_count'),
                    option_type=F('question__option_type'))
        bulk_create_survey_question = []
        survey_qs_cate_id_lst = []
        for i in question_qs:
            category_id = i.pop('category_id')
            i['survey_qs_cate_id'] = survey_qs_cate_dict[category_id]
            survey_qs_cate_id_lst.append(i['survey_qs_cate_id'])    # 加进去用于下一步进行查询
            bulk_create_survey_question.append(SurveyQuestion(**i))
        # 批量创建后重新查询，因为批量创建没返回新创建数据的id
        SurveyQuestion.objects.bulk_create(bulk_create_survey_question, batch_size=200)
        survey_question_qs = SurveyQuestion.objects\
            .filter(survey_qs_cate_id__in=survey_qs_cate_id_lst)\
            .values('id', 'question_id')
        survey_question_dict = {i['question_id']: i['id'] for i in survey_question_qs}

        # 找出这些问题的选项，并在调查中创建
        question_option_qs = QuestionOption.objects.filter(question_id__in=survey_question_dict)\
            .values('num', 'name', 'file', 'score', 'question_id', 'is_answer')
        bulk_create_survey_question_option = []
        for i in question_option_qs:
            i['question_id'] = survey_question_dict[i['question_id']]
            bulk_create_survey_question_option.append(SurveyQuestionOption(**i))
        SurveyQuestionOption.objects.bulk_create(bulk_create_survey_question_option, batch_size=200)

        return obj

    class Meta:
        model = Survey
        fields = ['start_time', 'end_time', 'name', 'desc', 'module', 'display_score_type',
                  'display_score_time', 'account', 'upload_student', 'questionnaire', 'class_cascader']


class SurveyUpdateSerializer(serializers.ModelSerializer):
    upload_student = serializers.JSONField(write_only=True)
    class_cascader = serializers.JSONField(write_only=True)

    def update(self, instance, validated_data):
        upload_student = validated_data.pop('upload_student', [])
        class_cascader = validated_data.pop('class_cascader', [])

        # 创建该场调查需要填写问卷的人员的信息
        class_code_lst = [i.split('_')[-1] for i in class_cascader]
        account_ids = Account.objects.filter(class_code__in=class_code_lst).values_list('id', flat=True)
        upload_student.extend(account_ids)
        bulk_create_account = []
        account_qs = Account.objects.filter(id__in=upload_student) \
            .values('username', 'realname', 'faculty_code', 'faculty_title', 'major_code', 'major_title', 'class_code',
                    'class_title', 'sex', 'grade_name')
        for i in account_qs:
            bulk_create_account.append(SurveyAccount(survey=instance, **i))
        SurveyAccount.objects.bulk_create(bulk_create_account, batch_size=200, ignore_conflicts=True)

        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        
        return instance

    class Meta:
        model = Survey
        fields = ['name', 'start_time', 'end_time', 'desc', 'display_score_type', 'display_score_time',
                  'upload_student', 'class_cascader']


class SurveyRetrieveSerializer(serializers.ModelSerializer):

    def to_representation(self, instance):
        ret = super().to_representation(instance)

        cate_ids = SurveyQuestionCategory.objects.filter(survey=instance).values_list('id', flat=True)
        qs = SurveyQuestion.objects.filter(survey_qs_cate_id__in=cate_ids, type__in=[3, 4]).values()
        ret['zg_question'] = []
        for i in qs:
            name = i['name']
            score = i['score']
            qs_id = i['id']

            zg_dict = {
                'name': f'{name}({score})',
                'code_name': f'zg_{qs_id}',
                'full_score': score,
                'id': qs_id
            }

            ret['zg_question'].append(zg_dict)
        # 主观题
        # ret['zg_question'] = [
        #     {'name': '这里是主观题1的题目(5分)', 'code_name': 'zg_1', 'full_score': 5, 'id': 1},
        #     {'name': '这里是主观题2的题目(15分)', 'code_name': 'zg_2', 'full_score': 15, 'id': 2},
        #     {'name': '这里是主观题3的题目(25分)', 'code_name': 'zg_3', 'full_score': 25, 'id': 3},
        #     {'name': '这里是主观题4的题目(15分)', 'code_name': 'zg_4', 'full_score': 15, 'id': 4},
        # ]
        return ret

    class Meta:
        model = Survey
        fields = ['name']


class SurveyAccountListSerializer(serializers.ModelSerializer):

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        account_data = self.context.get('account_data', None)
        options_dict = self.context.get('options_dict', {})
        zg_question_id_lst = self.context.get('zg_question_ids', [])
        if account_data is not None:
            personal_data = account_data.get(instance.id, {})
            ret['sum_score'] = personal_data['sum_score']   # 测评总分
            ret['fzg_score'] = personal_data['fzg_score']   # 非主观题的总分
            for i in zg_question_id_lst:
                zg_answer = personal_data['zg'][i]
                ret[f'zg_{i}'] = zg_answer['score'] if zg_answer['is_corrected'] else '未打分'
                ret[f'zg_{i}_answer'] = zg_answer['answer']
                ret[f'zg_{i}_survey_answer_id'] = zg_answer['id']

                # 回答的文件
                ret[f'zg_{i}_answer_file'] = []
                for j in zg_answer['file']:
                    file_path = j['url']
                    full_file_path = f"{settings.FILE_URL}{file_path}"
                    file_type = j['content_type'].split('/')[0]
                    file_type = file_type.lower()
                    file_dict = {
                        'name': j['name'], 'full_url': full_file_path, 'file_type': file_type
                    }
                    ret[f'zg_{i}_answer_file'].append(file_dict)
                ret[f'zg_{i}_answer_ls'] = None
                if zg_answer['answer_ls']:
                    answer_ls_str = []
                    for j in zg_answer['answer_ls']:
                        try:
                            j = int(j)
                        except ValueError:
                            continue
                        answer = options_dict.get(j, {})
                        answer_str = answer.get('num', '未知') + answer.get('name', '未知')
                        answer_ls_str.append(answer_str)
                    ret[f'zg_{i}_answer_ls'] = '/'.join(answer_ls_str)

        return ret

    class Meta:
        model = SurveyAccount
        fields = '__all__'


class SurveyAccountSerializer(serializers.ModelSerializer):
    last_submit_time = serializers.DateTimeField(format="%Y-%m-%d %H:%M:%S")

    def to_representation(self, instance):
        ret = super().to_representation(instance)
        account_data = self.context.get('account_data', {})
        ret['sum_score'] = account_data.get(instance.id, 0)
        # 返回填写状态
        status_dict = get_data_dict('survey_status', default_value={})
        ret['status_name'] = status_dict.get(instance.status, 'None')
        ret['use_time'] = str(instance.use_time) + '秒' if instance.use_time else None
        return ret

    class Meta:
        model = SurveyAccount
        fields = '__all__'


class SurveyAnswerUpdateSerializer(serializers.ModelSerializer):

    def update(self, instance, validated_data):
        question_full_score = instance.question.score
        question_type = instance.question.type
        if question_type in [1, 2]:
            raise serializers.ValidationError(detail=f"选择题不允许打分")
        if validated_data['score'] > question_full_score:
            raise serializers.ValidationError(detail=f"分数超过了该题目的满分值 {question_full_score} 分")

        validated_data['is_corrected'] = True   # 更新的话默认为已经批改
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance

    class Meta:
        model = SurveyAnswer
        fields = ['score']
